﻿--[[
  cache.lua（兼容版）
  目的：修复 “attempt to call a nil value (field 'keys')”
  做法：不再调用 fskv.keys，而是用 head/tail 索引实现队列。
  依赖：只用到 fskv.get / fskv.set / fskv.del（各固件均有）。

  API：
    cache.enqueue(pkt)         -- 入队一条 APRS 文本（string，无 \r
）
    cache.flush(send, ready)   -- 联网后补发，send(pkt)->true 表示成功；ready()->true 表示仍在线
    cache.count()              -- 返回队列长度
]]

local M = {}

-- 参数
local PREFIX   = "aprsq_"   -- 数据 key 前缀：aprsq_1, aprsq_2, ...
local KEY_HEAD = PREFIX.."head" -- 头指针（已发送的最后一个序号）
local KEY_TAIL = PREFIX.."tail" -- 尾指针（最新写入的序号）
local LIMIT    = 200         -- 最大缓存条数
local GAP_MS   = 300         -- 补发间隔，避免洪泛

-- 工具：安全取数
local function kv_get(k) local v = fskv and fskv.get and fskv.get(k) return v end
local function kv_set(k,v) if fskv and fskv.set then fskv.set(k,v) end end
local function kv_del(k) if fskv and fskv.del then fskv.del(k) end end

local function head_tail()
  local h = tonumber(kv_get(KEY_HEAD)) or 0
  local t = tonumber(kv_get(KEY_TAIL)) or 0
  return h, t
end

local function set_head(h) kv_set(KEY_HEAD, h) end
local function set_tail(t) kv_set(KEY_TAIL, t) end

-- 当前长度
function M.count()
  local h, t = head_tail()
  local n = t - h
  if n < 0 then n = 0 end
  return n
end

-- 入队
function M.enqueue(pkt)
  if type(pkt) ~= "string" or #pkt == 0 then return end
  local h, t = head_tail()
  while (t - h) >= LIMIT do
    h = h + 1
    kv_del(PREFIX..h)
  end
  t = t + 1
  kv_set(PREFIX..t, pkt)
  set_head(h); set_tail(t)
  log.info("cache", "enqueue", t - h)
  if wdt and wdt.feed then wdt.feed() end
end

function M.flush(send_func, is_ready)
  if type(send_func) ~= "function" or type(is_ready) ~= "function" then return end
  if not is_ready() then return end
  local h, t = head_tail()
  if t <= h then return end
  log.info("cache", "flush start", t - h)
  while is_ready() and h < t do
    local k = h + 1
    local key = PREFIX..k
    local pkt = kv_get(key)
    if pkt and #pkt > 0 then
      local ok, err = pcall(send_func, pkt)
      if ok and err ~= false then
        -- 发送成功（send_func 返回 true/非 false 即视为成功）
        kv_del(key)
        h = k
        set_head(h)
        sys.wait(GAP_MS)
        if wdt and wdt.feed then wdt.feed() end
      else
        -- 发送失败，保留，结束本轮
        log.warn("cache", "send fail, keep", key)
        break
      end
    else
      -- 空洞，直接跳过并清理
      kv_del(key)
      h = k
      set_head(h)
    end
  end
  log.info("cache", "flush done", M.count())
end

return M




